package cz.proks.simplecalendarmanager.server.servlet;

import java.net.URL;
import java.text.MessageFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.HiddenProperty;
import com.google.gdata.data.extensions.When;

import cz.proks.simplecalendarmanager.client.service.CalendarService;
import cz.proks.simplecalendarmanager.server.Configuration;
import cz.proks.simplecalendarmanager.server.utils.CalendarUtils;
import cz.proks.simplecalendarmanager.shared.ClientConstants.AppScope;
import cz.proks.simplecalendarmanager.shared.model.Calendar;
import cz.proks.simplecalendarmanager.shared.model.CalendarEvent;

public class CalendarServiceImpl extends GAuthentificatedRemoteServiceServlet implements CalendarService {
	private final static Logger log = Logger.getLogger(CalendarServiceImpl.class.getSimpleName());
	
	private final static URL LIST_ALL_CALENDARS_URL;
	private final static String LIST_ALL_CALENDAR_EVENTS = "https://www.google.com/calendar/feeds/{0}/private/full";
	
	static {
		try {
			LIST_ALL_CALENDARS_URL = new URL("https://www.google.com/calendar/feeds/default/owncalendars/full");			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	
	@Override
	public List<Calendar> list(Date from, Date to) {
		log.info("list():: start");
		
		List<Calendar> calendars = new LinkedList<Calendar>();
		
		try {
			CalendarFeed results = getAuthentificatedService().getFeed(LIST_ALL_CALENDARS_URL, CalendarFeed.class);
			
			log.info("list():: calendars=" + results.getEntries().size());
			for (CalendarEntry calendarEntry : results.getEntries()) {
				Calendar calendar = toSCMCalendar(calendarEntry);
				
				List<CalendarEventEntry> calendarEventEntries = listEventFeedsForCalendarEntry(calendarEntry, from, to);
				calendar.setEvents(toSCMCalendarEvents(calendarEntry, calendarEventEntries));
				
				calendars.add(calendar);				
			}
									
		} catch (Exception ex) {
			removeAccessTokenFromSession(AppScope.CALENDAR.getIdentifier());
			log.log(Level.WARNING, "list():: ", ex);			
		}
		
		log.info("list():: exit");
		return calendars;
	}

	@Override
	public void addEvent(CalendarEvent event) {
		// TODO Auto-generated method stub

	}

	@Override
	public void modifyEvent(CalendarEvent event) {
		// TODO Auto-generated method stub

	}

	@Override
	public void deleteEvent(CalendarEvent event) {
		// TODO Auto-generated method stub

	}
	
	@Override
	protected com.google.gdata.client.calendar.CalendarService getAuthentificatedService() throws OAuthException {		
		com.google.gdata.client.calendar.CalendarService service = new com.google.gdata.client.calendar.CalendarService(Configuration.getApplicationName());
		authentificate(service, AppScope.CALENDAR);
		return service;
	}
	
	private Calendar toSCMCalendar(CalendarEntry calendarEntry) {
		Calendar calendar = new Calendar();
		
		calendar.setId(calendarEntry.getId());
		calendar.setTitle(calendarEntry.getTitle() != null ? calendarEntry.getTitle().getPlainText() : "");
		calendar.setSummary(calendarEntry.getSummary() != null ? calendarEntry.getSummary().getPlainText() : "");
		calendar.setHidden(calendarEntry.getHidden().getValue().equals(HiddenProperty.TRUE.getValue()));
		calendar.setTimeZone(calendarEntry.getTimeZone().getValue());
		
		return calendar;
	}
	
	private CalendarEvent toSCMCalendarEvent(CalendarEntry cal, CalendarEventEntry eventEntry) {
		CalendarEvent calendarEvent = new CalendarEvent();
		
		calendarEvent.setCalendarId(cal.getId());
		calendarEvent.setId(eventEntry.getId());
		calendarEvent.setTitle(eventEntry.getTitle() != null ? eventEntry.getTitle().getPlainText() : "");
		calendarEvent.setContent(eventEntry.getPlainTextContent());
		
		When time = eventEntry.getTimes().isEmpty() ? null : eventEntry.getTimes().get(0);		
		calendarEvent.setStartTime(time != null ? time.getStartTime().toString() : "");
		calendarEvent.setEndTime(time != null ? time.getEndTime().toString() : "");
		
		return calendarEvent;
	}
	
	private List<CalendarEvent> toSCMCalendarEvents(CalendarEntry cal, List<CalendarEventEntry> eventEntries) {
		List<CalendarEvent> calendarEvents = new LinkedList<CalendarEvent>();
		
		for(CalendarEventEntry eventEntry : eventEntries) {
			CalendarEvent calendarEvent = toSCMCalendarEvent(cal, eventEntry);
			calendarEvents.add(calendarEvent);
		}
		
		return calendarEvents;
	}
	
	private List<CalendarEventEntry> listEventFeedsForCalendarEntry(CalendarEntry calendarEntry, Date from, Date to) {
		log.info("listEventFeedsForCalendarEntry():: start");
		
		List<CalendarEventEntry> eventEntries = new LinkedList<CalendarEventEntry>();
		
		try {			
			String query = MessageFormat.format(LIST_ALL_CALENDAR_EVENTS, CalendarUtils.getCalendarId(calendarEntry));			
			CalendarQuery calendarQuery = new CalendarQuery(new URL(query));
			
			calendarQuery.setMinimumStartTime(new DateTime(from));
			calendarQuery.setMaximumStartTime(new DateTime(to));
			
			log.info("listEventFeedsForCalendarEntry():: query=" + calendarQuery.getFeedUrl());
						
			CalendarEventFeed results = getAuthentificatedService().getFeed(calendarQuery, CalendarEventFeed.class);
			log.info("listEventFeedsForCalendarEntry():: calId=" + calendarEntry.getId() + ", events=" + results.getEntries().size());
			
			for(CalendarEventEntry calendarEvent : results.getEntries()) {
				eventEntries.add(calendarEvent);
			}						
		} catch(Exception ex) {
			log.log(Level.WARNING, "listEventFeedsForCalendarEntry():: ", ex);
		}
				
		log.info("listEventFeedsForCalendarEntry():: exit");
		
		return eventEntries;
	}
}
